
from django.shortcuts import Http404, render_to_response, HttpResponseRedirect
from django.core.urlresolvers import get_callable
from django.template import RequestContext
from django.utils.safestring import mark_safe
from django.contrib import messages

from apps.course.models import Course
from apps.course.functions import course_reverse
from apps.participants.models import CourseParticipant
from options import Options
from apps.management import Management

import os
import logging

logger = logging.getLogger('pet.apps.management.views')

def manage(request, course=None, app = None, command='manage', arguments=None, iframe=None):
    """
    This serves as an interface to manage multiple apps from one location.
    
    To use this interface, create a "manage.py" file with the views you want
    handled by the management interface. The required arguments to the view
    are (request, TheCourseParticipant, TheCourse, ...) where:
     - request - the usual request argument to a view
     - TheCourseParticipant - the CourseParticipant object related to the user
        accessing the view. Will be None if the user is a superuser but not
        associated with the course.
     - TheCourse - the Course object for the course that is being managed
     - ... - any other arguments given to the view as an ampersand-separated
        string in the url (each item will be included individually here)
    Example:
        edit(request, TheCourseParticipant, TheCourse, category=None, title=None)
        
    Then the view must be registered using:
    Management.register_interface(App Name,Users,Command,function,indirect=False) where:
     - App Name - the name of the app this function is associated with (functions
        are accessed by App name when calling the view)
     - Users - a semicolon-separated list of which type of user can access the
        view (options are ASSISTANT, INSTRUCTOR, SUPERUSER)
     - Command - the name that will be used to access the function in a url
        (any unserscores are converted to spaces when displaying the name in the
        breadcrumbs)
     - function - the function to be called
     - indirect (Optional, default=False) - this sets up the function as part of
        an indirect interface - no tab will be created for an app with only
        indirect interfaces
    Example:
        Management.register_interface("Files","INSTRUCTOR;ASSISTANT;SUPERUSER","manage",manage,indirect=True)
    
    The management interface will call your view function and insert the rendered
        content you return into the management view (which automatically includes
        "base.html" so you shouldn't use it in your management views). This
        includes a tab for each app that has non-indirect interfaces registered
        (each tab will be a link to that app's "manage" command, which is the
        default command when no other is given).
        
    There are some additional things that can be added to the returned HttpResponse
        that will change what the management interface does with the returned
        content:
        - HTTP Response Code outside the 200's - this will cause the management
            interface to return the Http Response directly instead of wrapping
            it in the management interface HTML. This is so any redirects or
            404s function properly.
        - HTTP Response Content-type - if this is not text/html, it is
            interpreted as an additional command to the management interface
            which will be removed. The current commands available are:
            - "no-management:" - This tells the management interface to not
                wrap the resulting html in the management html.
    """
    logger.fxn_entry("course %s, app %s, command %s, arguments %s, iframe %s",course, app, command, arguments, iframe)
    #Get required info about the current user
    TheCourse = Course.find_or_404(course)
    if not request.user.is_authenticated():
        messages.info(request,"Access to this part of the site requires course authentication and authorization")
        logger.forced_redirect('Unauthenticated user attempting to use management')
        return HttpResponseRedirect(course_reverse('course_index',TheCourse))

    TheCourseParticipant = CourseParticipant.find(TheCourse.course_id, request.user)
    
    #Make sure the app requested exists and that the user can access it
    CommandDict = {}
    Title = ''
    AllowedAppsDict = {}
    status = TheCourseParticipant.status if TheCourseParticipant else None
    if request.user.is_superuser and TheCourse.course_id == "__default": status = "INSTRUCTOR"
    
    #Check direct interfaces
    for app_title, commands in Management.get_interfaces().items():
        if not Options.is_enabled(True,app_title.capitalize()): continue
        if status in commands:
            AllowedAppsDict[app_title] = commands[status]
            if app and app_title.lower() == app.lower():
                CommandDict.update(commands[status])
                Title = app_title
        if request.user.is_superuser and "SUPERUSER" in commands:
            AllowedAppsDict[app_title] = commands["SUPERUSER"]
            if app and app_title.lower() == app.lower():
                CommandDict.update(commands["SUPERUSER"])
                Title = app_title
                
    #Check indirect interfaces
    for app_title, commands in Management.get_indirect_interfaces().items():
        if status in commands:
            if app and app_title.lower() == app.lower():
                CommandDict.update(commands[status])
                Title = app_title
        if request.user.is_superuser and "SUPERUSER" in commands:
            if app and app_title.lower() == app.lower():
                CommandDict.update(commands["SUPERUSER"])
                Title = app_title
            
    if app and not CommandDict:
        logger.http404("App %s not found or not authorized for user %s",app,request.user)
        raise Http404
    
    if not AllowedAppsDict:
        logger.forced_redirect("User %s has nothing they can manage for course %s (%s)",request.user, TheCourse,_ManagementInterfaces)
        return HttpResponseRedirect(course_reverse('course_index',TheCourse))
        
    #Change the dict to a list and sort for displaying
    AllowedApps = sorted(AllowedAppsDict.keys())
    
    #If no app was specified, get the first item and make that the app
    if not app:
        for default in Options.get_option('Default Tab','').split(';'):
            if default in AllowedApps:
                Title = default
                break;
        if not Title: Title = AllowedApps[0]
        CommandDict.update(AllowedAppsDict[Title])
    
    #Check the command
    if not command in CommandDict:
        logger.http404("Command %s not available in app %s",command, app)
        logger.http404("Available commands are: %s",CommandDict.keys())
        raise Http404
    
    #set the view
    view = CommandDict[command]
    
    #Render the app's management view to a string
    if arguments:
        AppResponse = get_callable(view)(request, TheCourseParticipant, TheCourse, *arguments.split('&'))

    else:
        AppResponse = get_callable(view)(request, TheCourseParticipant, TheCourse)
        
    #Check if appresponse is correct
    if AppResponse.status_code < 200 or AppResponse.status_code > 299:
        #Redirect, error, etc. just return the response
        return AppResponse
    if AppResponse.has_header('Content-Type') and not AppResponse.get("Content-Type","text/html").startswith('text/html'):
        if AppResponse["Content-Type"].startswith("no-management:"):
            AppResponse['Content-Type'] = AppResponse['Content-Type'].replace("no-management:",'')
        return AppResponse
    
    #Replace underscores with spaces in command
    command = command.replace('_',' ')
    Response = render_to_response('management/manage.html',{'content':mark_safe(AppResponse.content), 'command':command,
                                'AppTitle':Title, 'Apps':AllowedApps, 'iframe':iframe == 'iframe'}, context_instance=RequestContext(request))
    Response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    Response['Expires'] = -1
    Response['Pragma'] = 'no-cache, no-store'
    logger.fxn_exit("Returning")
    return Response
